home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / ALLOC.C next >
Text File  |  1993-11-23  |  30KB  |  1,010 lines

  1. /*======================================================================
  2. *  File Name:  alloc.c                                                  *
  3. *  Purpose  :  memory allocation routines                               *
  4. * Allocation routines. changed from K&R to the use of TURBO C++ offered *
  5. * routines. This is probably not a very portable solution, but it gives *
  6. * at least some relief when used under (MS)DOS.                         *
  7. *                                                                       *
  8. *  Date          Name         Description                               *
  9. *  ----          ----         -----------                               *
  10. *  04-apr-1991   AA6HM/DK5DC  initial implementation                    *
  11. *  09-apr-1991   AA6HM/DK5DC  added memory record                       *
  12. *  11-apr-1991   AA6HM/DK5DC  added crashdump facility                  *
  13. *  14-apr-1991   AA6HM/DK5DC  changed crashdump to ask Turbo C++ via    *
  14. *                             heapchecknode(),if he agrrees to dump and *
  15. *                             exit because of a corrupted node          *
  16. *=======================================================================*/
  17. #define __ALLOC_C 1
  18.  
  19. #include <stdio.h>
  20. #include <dos.h>
  21. #include <alloc.h>
  22. #include <fcntl.h>                      /* for filemodes DK5DC          */
  23. #include <io.h>                         /* for creattemp()              */
  24. #include <ctype.h>                        /* for isprint                     */
  25. #include <conio.h>
  26. #include "global.h"
  27. #include "config.h"
  28. #include "proc.h"
  29. #include "cmdparse.h"
  30. #include "mbuf.h"
  31. #include "session.h"
  32. #include "files.h"
  33. #include "commands.h"                    /* for doexit()                 */
  34.  
  35. #ifdef __CPLUSPLUS
  36. #define Free 0
  37. #define Used 1
  38. #define Over 2
  39. #endif
  40.  
  41. /* Free memory threshold, below which things start to happen to conserve
  42.  * memory, like garbage collection, source quenches and refusing connects
  43.  */
  44. static int32 Memthresh = (int32)MTHRESH;           /* to be sure - db3fl */
  45.  
  46. static int32 Intalloc = 0;   /* Calls to malloc with ints disabled  */
  47. static int32 Memfail = 0;    /* Count of allocation failures        */
  48. static int32 Allocs = 0;     /* Total allocations                   */
  49. static int32 Frees = 0;      /* Total frees                         */
  50. static int32 Intfree = 0;    /* Calls to free with ints disabled    */
  51.  
  52. #if(defined(PACKET) || defined(ETHER) || defined(SCC))
  53. static int16 Ibufsize = IBUFSIZE;    /* Size to allocate                    */
  54. static int Nibufs = NIBUFS;             /* Number of Int-buffers               */
  55. #else
  56. static int16 Ibufsize = 1;
  57. static int Nibufs = 1;
  58. #endif
  59.  
  60. static int Intqlen = 0;        /* Number of free mbufs on Intq */
  61. static int Memwait = 0;     /* Number of tasks waiting for memory  */
  62. static int Memcold = FALSE;        /* controls rebooting when memory goes low */
  63.  
  64. static struct mbuf *Intq = NULLBUF;   /* Mbuf pool for interrupt handlers */
  65. static struct mbuf *Garbq = NULLBUF;  /* List of buffers freed at interrupt time */
  66.  
  67. #ifdef MDEBUG
  68. static int32 Sizes[16];
  69. static FILE *rfp = 0;            /* points to memrecord                 */
  70. static int rflag = 0;
  71. int binver = 0x5010;
  72.  
  73. #endif
  74.  
  75. #ifdef MDEBUG
  76. #  define PARA 16
  77. #  define UNIT 8
  78. #  define ALLOC "\xAA"           /* marker for alloc                    */
  79. #  define FREE  "\x55"           /* marker for free                     */
  80.  
  81. /*----------------------------------------------------------------------*
  82. * template to access inserted debug info                                *
  83. *-----------------------------------------------------------------------*/
  84. typedef struct {
  85.    unsigned line;
  86.    char file[10];
  87. }Hd;
  88.  
  89. #else
  90.  
  91. /*----------------------------------------------------------------------*
  92. * template to access Turbo C++'s memory linkages
  93. *-----------------------------------------------------------------------*/
  94. typedef struct   {
  95.    unsigned np;                  /* noOfParagraphs in block             */
  96.    unsigned seg;                 /* used: link to previous segment      */
  97.    unsigned backseg,forseg;      /* free freelist linkage               */
  98. }Id;
  99.  
  100. #define Hd char
  101. #endif
  102.  
  103. /*----------------------------------------------------------------------*
  104. * the three variables below are maintained by C++ to mark the start and *
  105. * the end of the used heap                                              *
  106. *-----------------------------------------------------------------------*/
  107. #ifdef __CPLUSPLUS
  108. extern unsigned far __first;
  109. extern unsigned far __last;
  110. extern unsigned far __rover;
  111.  
  112. static Hd huge * near checkheap __ARGS((void));
  113. #endif
  114.  
  115. #ifdef MDEBUG
  116. static int near dump __ARGS((Hd huge *cret));
  117. #endif
  118.  
  119. /*----------------------------------------------------------------------*
  120. * Set the C++ roving memory pointer to the first  free block            *
  121. *-----------------------------------------------------------------------*/
  122. static void near
  123. _setrover(void)
  124. {
  125. struct heapinfo hp;
  126.  
  127.    hp.ptr = 0;
  128.    while(heapwalk(&hp) != _HEAPEND) {
  129.       if(hp.in_use == 0) {
  130.          __rover = FP_SEG(hp.ptr);
  131.          break;
  132.       }
  133.    }
  134. }
  135.  
  136. /*----------------------------------------------------------------------*
  137. * Allocate block of 'nb' bytes                                          *
  138. *-----------------------------------------------------------------------*/
  139. #ifdef MDEBUG
  140. void *
  141. mxalloc(char *file,unsigned line,unsigned nb)
  142. #else
  143. void *
  144. mxalloc(unsigned nb)
  145. #endif
  146. {
  147. Hd *node;
  148.  
  149. #ifdef MDEBUG
  150. unsigned foo = nb;
  151. int i;
  152. struct time stime;
  153. #endif
  154.  
  155.    if(!istate()) {
  156.       Intalloc++;
  157.    }
  158.    /*-------------------------------------------------------------------*
  159.    * If memory is below Memthresh, reboot the system. This seemes to be *
  160.    * a more secure way to prevent garbage and 'unexpected modes'.       *
  161.    *--------------------------------------------------------------------*/
  162.    if(availmem() == 0) {
  163.       if(Memcold) {
  164.         void far (*foo) __ARGS((void));
  165.  
  166.         /* FFFF:0000 is hardware reset vector */
  167.         foo = MK_FP(0xffff,0);
  168.  
  169.         (*foo)();               /* no return */
  170.       } else {
  171.         char *arg[3];
  172.         arg[1] = "252";
  173.         doexit(0,arg,0);
  174.       }
  175.    }
  176.    if(nb == 0) {
  177.       return NULL;
  178.    }
  179.    _setrover();
  180.  
  181. #ifdef MDEBUG
  182.    /*-------------------------------------------------------------------*
  183.    * Record the size of this request                                    *
  184.    *--------------------------------------------------------------------*/
  185.    for(i = 0; i < 16; i++) {
  186.       if(foo >= 32768L) {
  187.          break;
  188.       }
  189.       foo <<= 1;
  190.    }
  191.    Sizes[15-i]++;
  192.  
  193.    /*-------------------------------------------------------------------*
  194.    * the calloc() is merely a circumvention, cause I'm unable to find   *
  195.    * ALL the uninitialized 'next ptr's' in that whole crop of NOS       *
  196.    * functions. calloc() makes sure to get (zero) initialized memory    *
  197.    *--------------------------------------------------------------------*/
  198.    if((node = calloc(1,nb + PARA)) != 0) {
  199.       /*----------------------------------------------------------------*
  200.       * insert the line/file info passed when MDEBUG is on              *
  201.       *-----------------------------------------------------------------*/
  202.       strncpy(node->file,file,8);
  203.       node->line = line;
  204.       /*----------------------------------------------------------------*
  205.       * if recording is on, build a record and write it into the file   *
  206.       *-----------------------------------------------------------------*/
  207.       if (rflag)   {
  208.          unsigned seg;
  209.          /*-------------------------------------------------------------*
  210.          * use dostime(), cause it calculates much faster than time()   *
  211.          * and has a granularity of 10 milliseconds                     *
  212.          *--------------------------------------------------------------*/
  213.          gettime(&stime);
  214.          fwrite(ALLOC,1,1,rfp);         /* write the marker             */
  215.          seg = FP_SEG((char *)node-4);  /* alloce'd segment             */
  216.          fwrite(&stime,sizeof(struct time),1,rfp);
  217.          fwrite(&seg,sizeof(unsigned),1,rfp);
  218.          fwrite(((char *)node-4),PARA,1,rfp);
  219.       }
  220.       Allocs++;
  221.       return(node+1);
  222.    }
  223. #else    /* MDEBUG */
  224.    if((node = calloc(1,nb)) != 0) {
  225.         Allocs++;
  226.         return(node);
  227.    }
  228. #endif
  229.  
  230.    Memfail++;
  231.    return NULL;
  232. }
  233.  
  234. /*----------------------------------------------------------------------*
  235. * Put memory block back on heap                                         *
  236. *-----------------------------------------------------------------------*/
  237. #ifdef MDEBUG
  238. void
  239. xfree(char *file,unsigned line,void *b)
  240. #else
  241. void
  242. xfree(void *b)
  243. #endif
  244. {
  245. #ifdef __CPLUSPLUS
  246.     Hd huge *cret;
  247. #endif
  248. #ifdef MDEBUG
  249.     Hd huge *blk = (Hd *)b - 1;
  250. #endif
  251.  
  252.     if(!istate()) {
  253.         Intfree++;
  254.     }
  255.     if(b == NULL) {
  256.         return;                           /* Required by ANSI             */
  257.     }
  258.  
  259. #ifdef __CPLUSPLUS
  260.     /*-------------------------------------------------------------------*
  261.     * make the audit check
  262.     *--------------------------------------------------------------------*/
  263.     if((cret = checkheap()) != 0) {
  264.         dirps();
  265.         iostop();
  266. #ifdef MDEBUG
  267.         printf("\nfree(): corrupted Node (%Fp) %10.10s %05u proc %s\n\n",
  268.             cret,cret->file,cret->line,Curproc->name);
  269.         dump(cret);                       /* POOF!!!!!                    */
  270. #else
  271.         printf("\nfree(): corrupted Node (%Fp) proc %s\n\n",
  272.             cret,Curproc->name);
  273. #endif
  274.         exit(255);
  275.     }
  276. #endif
  277.  
  278. #ifdef MDEBUG
  279.       else if (rflag)   {
  280.         struct time stime;
  281.         unsigned seg = FP_SEG((char *)blk - 4;
  282.  
  283.         gettime(&stime);
  284.         fwrite(FREE,1,1,rfp);
  285.         fwrite(&stime,sizeof(struct time),1,rfp);
  286.         fwrite(&seg,sizeof(unsigned),1,rfp);
  287.         fwrite(((char *)blk - 4),PARA,1,rfp);
  288.         seg = line;
  289.         fwrite(&seg,sizeof(unsigned),1,rfp);
  290.         fwrite(file,10,1,rfp);
  291.     }
  292. #endif
  293.  
  294. #ifdef MDEBUG
  295.     free((void *)blk);
  296. #else
  297.     free(b);
  298. #endif
  299.  
  300.     Frees++;
  301.     semrel(&Memwait);
  302. }
  303.  
  304. #ifdef MDEBUG
  305. /*----------------------------------------------------------------------*
  306. * Dump the memory in case of an error detected by checkheap and exit..  *
  307. * low level routines are used.....                                      *
  308. *-----------------------------------------------------------------------*/
  309. static int near
  310. dump(Hd huge *cret)
  311. {
  312. int fd, seg, fmode;
  313. char huge *para;
  314. extern struct timer *Timers;
  315. struct timer *tp;
  316. int i_state;
  317. char path[MAXPATH];
  318.  
  319.    strcpy(path,getenv("HOME"));
  320.    strcat(path,"\\");;
  321.    fmode = _fmode;                      /* preserve filemode            */
  322.    _fmode = O_BINARY;
  323.    if ((fd=creattemp(path,0))<0)   {
  324.       _fmode = fmode;
  325.       return(-1);
  326.    }else {
  327.       i_state = dirps();
  328.       tprintf("Memory dump started...file = %s\n\r",path);
  329.       write(fd,&binver,2);              /* write version                */
  330.       write(fd,&__first,2);             /* write __first ptr            */
  331.       write(fd,&__last,2);              /* write __last ptr             */
  332.       write(fd,&__rover,2);             /* write __rover ptr            */
  333.       write(fd,&cret,4);                /* save error position          */
  334.       write(fd,(char *)cret-4,16);      /* save suspected header        */
  335.       /*----------------------------------------------------------------*
  336.       * save processing queue ptrs...                                   *
  337.       *-----------------------------------------------------------------*/
  338.       write(fd,&Curproc,sizeof(struct proc *));
  339.       write(fd,&Rdytab,sizeof(struct proc *));
  340.       write(fd,&Susptab,sizeof(struct proc *));
  341.       write(fd,&Waittab,16*sizeof(struct proc *));
  342.       /*----------------------------------------------------------------*
  343.       * save the Timerchain.....                                        *
  344.       *-----------------------------------------------------------------*/
  345.       for (tp = Timers;tp;tp = tp->next)
  346.          write(fd,tp,sizeof(struct timer ));
  347.       /*----------------------------------------------------------------*
  348.       * save session control blocks                                     *
  349.       *-----------------------------------------------------------------*/
  350.       seg = NSESSIONS;
  351.       write(fd,&seg,sizeof(int));
  352.       write(fd,Sessions,sizeof(struct session)*Nsessions);
  353.       /*----------------------------------------------------------------*
  354.       * save the file descriptors, at least the first 16...             *
  355.       *-----------------------------------------------------------------*/
  356.       write(fd,(char *)&_streams,16*sizeof(FILE));
  357.       /*----------------------------------------------------------------*
  358.       * now dump the whole heap... maybe expanded to whole system       *
  359.       * sessions,tcb's etc  to get a snapshot of the system             *
  360.       *-----------------------------------------------------------------*/
  361.       for (seg = __first;seg<__last;seg++)   {
  362.          para = MK_FP(seg,0);
  363.          write(fd,(void *)para,PARA);
  364.       }
  365.       close(fd);
  366.    }
  367.    restore(i_state);
  368.    _fmode = fmode;
  369.    return(0);
  370. }
  371. #endif
  372.  
  373. /*----------------------------------------------------------------------*
  374. * This is a very rough check routine. As I dive into the code           *
  375. * the routine might be streamlined  DK5DC                               *
  376. * As far as I could find the facts, the C++ memory links are built as   *
  377. * follows:                                                              *
  378. *      1.  Memory is ALWAYS allocated on a paragraph (16 Byte) Basis    *
  379. *          TC++ ALWAYS returns a address in the form                    *
  380. *          Segment:0004. The first four bytes in the first paragraph are*
  381. *          used for size and link informations. The first two bytes     *
  382. *          contain the size of the block in paragraphs                  *
  383. *          The remaining two bytes contain a segment address pointing   *
  384. *          to the previous (allocated block) or to (^self).             *
  385. *      2.  A FREE entry uses two more byte pairs for header information *
  386. *           (This caused some bad NOS crashes when some code was running*
  387. *            along a linked list, a block was freed, the 'next'pointer  *
  388. *            was defined as the first member of the structure and NOS   *
  389. *            tried to access that ptr AFTER freeing the block)          *
  390. *          Anyway, those two pairs of code contain a backward           *
  391. *          and forward pointer to its free neighbours.                  *
  392. *-----------------------------------------------------------------------*/
  393. #ifdef __CPLUSPLUS
  394. static Hd huge * near
  395. checkheap(void)
  396. {
  397.    unsigned prev;
  398.    unsigned last = __last;
  399.    unsigned run = prev = __first;
  400.    Id huge *rp = 0;
  401.  
  402.    /*-------------------------------------------------------------------*
  403.    * scan the heap                                                      *
  404.    *--------------------------------------------------------------------*/
  405.    while (run < last)   {
  406.       rp = MK_FP(run,0);
  407.       /*----------------------------------------------------------------*
  408.       * make the test                                                   *
  409.       *-----------------------------------------------------------------*/
  410.       if (rp->seg != NULL && rp->seg != prev)   {
  411.          rp = MK_FP(run,4);
  412.          /*-------------------------------------------------------------*
  413.          * before getting nasty, ask C++ to check again...              *
  414.          *--------------------------------------------------------------*/
  415.          if(heapcheck() < 0) {
  416.             rp = MK_FP(prev,0);
  417.             return((Hd huge *)((char *)rp+4));
  418.          }
  419.       }
  420.       prev = run;
  421.       run += rp->np;
  422.    }
  423.    return(0);
  424. }
  425. #endif
  426.  
  427. /*----------------------------------------------------------------------*
  428. * Version of malloc() that waits if necessary for memory to become available *
  429. *-----------------------------------------------------------------------*/
  430. #ifdef MDEBUG
  431. void *
  432. mxallocw(char *file,unsigned line,unsigned nb)
  433. #else
  434. void *
  435. mxallocw(unsigned nb)
  436. #endif
  437. {
  438.     void *cp;
  439.  
  440.     semwait(&Memwait,1);
  441.     cp = mxalloc(nb);
  442.     semrel(&Memwait);
  443.     return cp;
  444. }
  445.  
  446. /*----------------------------------------------------------------------*
  447. * Version of calloc that waits if necessary for memory to become available *
  448. *-----------------------------------------------------------------------*/
  449. #ifdef MDEBUG
  450. void *
  451. cxallocw(char *file,unsigned line,unsigned nelem,unsigned size)
  452. #else
  453. void *
  454. cxallocw(unsigned nelem,unsigned size)
  455. #endif
  456. {
  457.     void *cp;
  458.  
  459.     semwait(&Memwait,1);
  460.     cp = mxalloc(nelem * size);
  461.     semrel(&Memwait);
  462.     return cp;
  463. }
  464.  
  465. /*----------------------------------------------------------------------*
  466. * Copy a string to a malloc'ed buffer. Turbo C has this one in its      *
  467. * library, but it doesn't call mallocw() and can therefore return NULL. *
  468. * NOS uses of strdup() generally don't check for NULL, so they need this*
  469. * one.                                                                  *
  470. *                                                                       *
  471. * Changed the name to strxdup and added the file/line pair insertion.   *
  472. * Otherwise only the malloc() would be recorded, which is always inside *
  473. * strxdup() and not the strdup location itself.                         *
  474. *-----------------------------------------------------------------------*/
  475. #ifdef MDEBUG
  476. char *
  477. strxdup(char *file,unsigned line,const char *s)
  478. #else
  479. char *
  480. strxdup(const char *s)
  481. #endif
  482. {
  483.     char *out;
  484.     int len = strlen(s);
  485.  
  486.     if(s == NULLCHAR || len == 0) {
  487.         return NULLCHAR;
  488.     }
  489.     semwait(&Memwait,1);
  490.     out = mxalloc(len+1);
  491.     semrel(&Memwait);
  492.  
  493.     /* This is probably a tad faster than strcpy, since we know the len */
  494.     memcpy(out,s,len);
  495.     return out;
  496. }
  497.  
  498. /* Check available memory */
  499. int
  500. availmem()
  501. {
  502.     return ((Memthresh * 2) < coreleft());
  503. }
  504.  
  505. #ifdef MDEBUG
  506. /*----------------------------------------------------------------------*
  507.  *----------------------------------------------------------------------*/
  508. static int
  509. dorefiq(int argc,char **argv,void *p)
  510. {
  511.     struct mbuf *bp = 0, *bp1 = 0;
  512.     int i_state;
  513.  
  514.     if(Garbq != NULLBUF){
  515.         i_state = dirps();                /* critical section             */
  516.         bp = Garbq;
  517.         Garbq = NULLBUF;
  518.         restore(i_state);
  519.         free_p(bp);
  520.     }
  521.     _setrover();
  522.     i_state = dirps();                   /* critical section             */
  523.     bp1 = Intq;
  524.     Intq = NULLBUF;
  525.     restore(i_state);
  526.     Intqlen = 0;
  527.     refiq();
  528.     free_p(bp1);
  529.     return 0;
  530. }
  531. #endif
  532.  
  533. void
  534. refiq(void)
  535. {
  536.     struct mbuf *bp;
  537.     int i_state;
  538.  
  539.     /* Empty the garbage */
  540.     if(Garbq != NULLBUF) {
  541.         i_state = dirps();
  542.         bp = Garbq;
  543.         Garbq = NULLBUF;
  544.         restore(i_state);
  545.         free_p(bp);
  546.     }
  547.     /* Replenish interrupt buffer pool */
  548.     while(Intqlen < Nibufs) {
  549.         bp = alloc_mbuf(Ibufsize);
  550.         i_state = dirps();
  551.         bp->next = Intq;
  552.         Intq = bp;
  553.         restore(i_state);
  554.         Intqlen++;
  555.     }
  556. }
  557.  
  558. /* Allocate mbuf with associated buffer of 'size' bytes. If interrupts
  559.  * are enabled, use the regular heap. If they're off, use the special
  560.  * interrupt buffer pool.
  561.  */
  562. #ifdef MDEBUG
  563. struct mbuf *
  564. alloc_mbuf(char *file,unsigned line, int16 size)
  565. #else
  566. struct mbuf *
  567. alloc_mbuf(int16 size)
  568. #endif
  569. {
  570.     struct mbuf *bp;
  571.  
  572.     if(istate()) {
  573.         /* Interrupts are enabled, use the heap normally */
  574.         bp = mxallocw((unsigned)(size + sizeof(struct mbuf)));
  575.  
  576.         if((bp->size = size) != 0) {
  577.             bp->data = (char *)(bp + 1);
  578.         }
  579.         bp->refcnt++;
  580.         bp->next = NULLBUF;
  581.     } else {
  582.         /* Interrupts are off, use special interrupt buffer pool */
  583.         if(size > Ibufsize) {
  584. #if(!(defined PACKET) && !(defined ETHER) && !(defined SCC))
  585.             Ibufsize = size;
  586.         }
  587. #else
  588.             char *arg[3];
  589.             arg[1] = "253";
  590.             printf("\nInterrupt buffer overflow (size %u def %u)\n\n",size,Ibufsize);
  591.             doexit(0,arg,0);
  592.         } else
  593. #endif
  594.         if(Intq == NULLBUF) {
  595.             Nibufs++;
  596.             bp = mxallocw(Ibufsize + sizeof(struct mbuf));
  597.             bp->size = Ibufsize;
  598.             bp->data = (char *)(bp + 1);
  599.             bp->refcnt++;
  600.             bp->next = Intq;
  601.             Intq = bp;
  602.         } else {
  603.             bp = Intq;
  604.             Intq = bp->next;
  605.             bp->next = NULLBUF;
  606.             Intqlen--;
  607.         }
  608.     }
  609.     return bp;
  610. }
  611.  
  612. /* Decrement the reference pointer in an mbuf. If it goes to zero,
  613.  * free all resources associated with mbuf.
  614.  * Return pointer to next mbuf in packet chain
  615.  */
  616. struct mbuf *
  617. #ifdef MDEBUG
  618. free_mbuf(char *file,unsigned line,struct mbuf *bp)
  619. #else
  620. free_mbuf(struct mbuf *bp)
  621. #endif
  622. {
  623.     struct mbuf *bp1 = bp->next;
  624.  
  625.     if(bp == NULLBUF) {
  626.         return NULLBUF;
  627.     }
  628.     if(bp->dup != NULLBUF) {
  629.         free_mbuf(bp->dup);                /* Follow indirection */
  630.         bp->dup = NULLBUF;
  631.     }
  632.     /* Decrement reference count. If it has gone to zero, free it. */
  633.     if(--bp->refcnt <= 0) {
  634.         if(istate()) {
  635.             xfree(bp);
  636.         } else {
  637.             /* If the interrupt pool isn't full and this buffer
  638.              * appears to have come from it, put it back.
  639.              * Otherwise put it on the garbage list where it
  640.              * will be freed by refiq() later with interrupts
  641.              * enabled.
  642.              *
  643.              * This test handles the common special case of
  644.              * an interrupt handler allocating a buffer and
  645.              * then freeing it before returning (e.g., due to
  646.              * a receive abort or CRC failure).
  647.              */
  648.             bp->refcnt = 1;    /* Adjust */
  649.  
  650.             if(bp->size == Ibufsize && Intqlen < Nibufs) {
  651.                 bp->anext = NULLBUF;
  652.                 bp->data = (char *)(bp + 1);
  653.                 bp->cnt = 0;
  654.                 bp->next = Intq;
  655.                 Intq = bp;
  656.                 Intqlen++;
  657.             } else {
  658.                 bp->next = Garbq;
  659.                 Garbq = bp;
  660.             }
  661.         }
  662.     }
  663.     return bp1;
  664. }
  665.  
  666. /*----------------------------------------------------------------------*
  667. *-----------------------------------------------------------------------*/
  668. #ifdef MDEBUG
  669. int
  670. openmemrec(char *name)
  671. {
  672.    if((rfp = Fopen(name,"w+b")) == NULLFILE)  {
  673.       tprintf("Unable to open record file %s\n\r",name);
  674.       return(-1);
  675.    }
  676.    fprintf(rfp,"THIS FILE CONTAINS BINARY DATA... use ANALMEM              \n\r\x1a");
  677.    fwrite(&binver,sizeof(int),1,rfp);
  678.    tprintf("record Memory allocations into %s\n\r",name);
  679.    rflag = 1;
  680.    return(0);
  681. }
  682. #endif
  683.  
  684. #ifdef MDEBUG
  685. /* Convert byte to two ascii-hex characters */
  686. static void near
  687. ctohex(char *buf,int16 c)
  688. {
  689.    static char hex[] = "0123456789abcdef";
  690.  
  691.    *buf++ = hex[hinibble(c)];
  692.    *buf = hex[lonibble(c)];
  693. }
  694.  
  695. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  696.  * translation, e.g.,
  697.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  698.  */
  699. static void near
  700. fmtline(FILE *fp,int16 addr,char *buf,int16 len,int type)
  701. {
  702. char line[81], *aptr, *cptr, c;
  703.  
  704.    memset(line,' ',sizeof(line));
  705.    ctohex(line,hibyte(addr));
  706.    ctohex(line+2,lobyte(addr));
  707.    aptr = &line[6];
  708.    cptr = &line[55];
  709.    while(len-- != 0){
  710.       c = *buf++;
  711.       ctohex(aptr,uchar(c));
  712.       aptr += 3;
  713.       c &= 0x7f;
  714.       *cptr++ = isprint(uchar(c)) ? c : '.';
  715.    }
  716.    *cptr++ = '\0';
  717.    if (type)
  718.       fprintf(fp,"%s\n\r",line);
  719.    else
  720.       tprintf("%s\n",line);
  721.    if (fp)
  722.       fwrite(line,1,(unsigned)(cptr-line),fp);
  723. }
  724. #endif
  725.  
  726. #ifdef __CPLUSPLUS
  727. static int near
  728. _checkok(void)
  729. {
  730.    if(heapcheck() != _HEAPOK) {
  731.       tputs("Heap doesn't check ok\n");
  732.       return(0);
  733.    }
  734.    return 1;
  735. }
  736. #endif
  737.  
  738. #ifdef __CPLUSPLUS
  739. /*-----------------------------------------------------------------------*/
  740. static int near
  741. getheap(int flag)
  742. {
  743.     struct heapinfo hp;
  744.     int i = 0;
  745.  
  746.     hp.ptr = 0;                          /* start at the beginning       */
  747.  
  748.     while(1)   {
  749.         if (heapwalk(&hp) == _HEAPEND) {
  750.             break;
  751.         }
  752. #ifdef MDEBUG
  753.         if(flag == Over) {
  754.             int j;
  755.  
  756.             for(j = 0; j < hp.size/16; j += 2) {
  757.                 if (i == 0) {
  758.                     tprintf("%04x ",FP_SEG(hp.ptr) + j);
  759.                 }
  760.                 tputs(hp.in_use ? "+" : "-");
  761.  
  762.                 if(++i == 72) {
  763.                     i = 0;
  764.                     tputs("\n");
  765.                 }
  766.             }
  767.         } else
  768. #endif
  769.         if(hp.in_use == flag) {
  770.             tprintf("%4x %5lu",FP_SEG(hp.ptr),hp.size);
  771.  
  772.             if(++i == 6) {
  773.                 i = 0;
  774.                 tputs("\n");
  775.             } else {
  776.                 tputs(" | ");
  777.             }
  778.         }
  779.    }
  780.    tputs("\nEnd of list\n");
  781.    return 0;
  782. }
  783. #endif
  784.  
  785.  
  786.  
  787.  
  788. /* ------------------------ Memory subcmds ---------------------------- */
  789.  
  790. #ifdef MDEBUG
  791. static char far *DumpAddr = NULL;           /* Memory dump pointer          */
  792.  
  793. int
  794. domdump(int argc,char **argv,void *p)
  795. {
  796. char *addr;
  797. unsigned int i, len = 8 * 16;          /* default is 8 lines of hex dump*/
  798. int seg;
  799.  
  800.    if((argc > 3 && DumpAddr == NULL) || (argc < 2 && DumpAddr == 0)) {
  801.       tputs("Usage: dump <segment|.> [decimal range]\n");
  802.       return 0;
  803.    }
  804.    if(argv[1][0] == '.' || argc == 1)
  805.       addr = DumpAddr;      /* Use last end address */
  806.    else
  807. #ifdef MEBUG
  808.       addr = (char *)(shtop(argv[1]))-16;   /* get address of item being dumped */
  809. #else
  810.       addr = (char *)(shtop(argv[1]))-4;       /* get address of item being dumped */
  811. #endif
  812.    seg = FP_SEG(addr);
  813.  
  814.    if(argc == 3) {
  815.       len = atoi(argv[2]);
  816.       len = ((len + 15) >> 4) << 4;   /* round up to modulo 16 */
  817.    }
  818.  
  819.    if(len < 1) len = 1;
  820.    if(len > 256) len = 256;
  821.  
  822.    tprintf("Main Memory Dump Of Location %Fp\n"
  823.            "Addr (offset)           Hexadecimal                         Ascii\n",
  824.            addr);
  825.  
  826.    for(i = 0; i < len; i += 16)
  827.       fmtline((FILE *)0,seg++, (char *)(addr+i),16,0);
  828.  
  829.    DumpAddr = MK_FP(seg,0);             /* update address               */
  830.    return 0;
  831. }
  832. #endif
  833.  
  834. static int
  835. docoldst(int argc,char **argv,void *p)
  836. {
  837.     return setbool(&Memcold,"Reboot",argc,argv);
  838. }
  839.  
  840. #ifdef __CPLUSPLUS
  841. /*----------------------------------------------------------------------*
  842. * Print heap free list                                                  *
  843. *-----------------------------------------------------------------------*/
  844. static int
  845. dofreelist(int argc,char **argv,void *p)
  846. {
  847.  
  848.    if (!_checkok()) {
  849.       return -1;
  850.    }
  851.    return (getheap(Free));
  852. }
  853. #endif
  854.  
  855. #if(defined(PACKET) || defined(ETHER) || defined(SCC))
  856. static int
  857. doibufsize(int argc,char **argv,void *p)
  858. {
  859.     return setintrc(&Ibufsize,"Int buffer size",argc,argv,0,MAXINT16);
  860. }
  861.  
  862. static int
  863. donibufs(int argc,char **argv,void *p)
  864. {
  865.     return setint(&Nibufs,"Int pool buffers",argc,argv);
  866. }
  867. #endif
  868.  
  869. #if((defined __CPLUSPLUS) && defined(MDEBUG))
  870. static int
  871. doOverview(int argc,char **argv,void *envp)
  872. {
  873.    if (!_checkok()) {
  874.       return -1;
  875.    }
  876.    return (getheap(Over));
  877. }
  878. #endif
  879.  
  880. #ifdef MDEBUG
  881. static int
  882. dorecord(int argc,char **argv,void *p)
  883. {
  884.  
  885.    if (argc < 2)   {
  886.       tprintf("Memory recording %s\n", rfp ? "on" : "off");
  887.       return(0);
  888.    }
  889.    if (!stricmp(argv[1],"off"))   {
  890.       if (rflag) {
  891.          Fclose(rfp);
  892.          rflag=0;
  893.       }
  894.       return(0);
  895.    }
  896.    if (rfp) {
  897.        Fclose (rfp);
  898.        rflag=0;
  899.    }
  900.    openmemrec(argv[1]);
  901.    return(0);
  902. }
  903. #endif
  904.  
  905. #ifdef MDEBUG
  906. static int
  907. dosizes(int argc,char **argv,void *p)
  908. {
  909.     int i;
  910.  
  911.     for(i = 0; i < 16; i += 4) {
  912.         tprintf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
  913.             1 << i,Sizes[i],2 << i,Sizes[i+1],
  914.             4 << i,Sizes[i+2],8 << i,Sizes[i+3]);
  915.     }
  916.     return 0;
  917. }
  918. #endif
  919.  
  920. #ifdef MDEBUG
  921. static int
  922. dosnap(int argc,char **argv,void *p)
  923. {
  924.     Hd cret;
  925.  
  926.     memset(&cret,0,sizeof(Hd));
  927.     strcpy(cret.file,"SnapDump");
  928.  
  929.     if (!dump(&cret)) {
  930.         tputs("Dump successfully written...\n");
  931.     } else {
  932.         tputs("Can't open Dumpfile...\n");
  933.     }
  934.     return 0;
  935. }
  936. #endif
  937.  
  938. /*----------------------------------------------------------------------*
  939. * Print heap stats                                                      *
  940. *-----------------------------------------------------------------------*/
  941. static int
  942. dostat(int argc,char **argv,void *p)
  943. {
  944.    tprintf("coreleft %lu allocs %lu frees %lu diff %lu invalid %lu\n"
  945.            "int-off calls to alloc %lu free %lu\n",
  946.             coreleft(),Allocs,Frees,Allocs-Frees,Memfail,Intalloc,Intfree);
  947. #if(defined(PACKET) || defined(ETHER) || defined(SCC))
  948.    tprintf("Intqlen %u Ibufsize %u\n",Intqlen,Ibufsize);
  949. #endif
  950.    return 0;
  951. }
  952.  
  953. static int
  954. dothresh(int argc,char **argv,void *p)
  955. {
  956.     return setlong(&Memthresh,"Mem threshold (bytes)",argc,argv);
  957. }
  958.  
  959. #if((defined __CPLUSPLUS) && defined(MDEBUG))
  960. /*----------------------------------------------------------------------*
  961. * Print heap used list                                                  *
  962. *-----------------------------------------------------------------------*/
  963. static int
  964. dousedlist(int argc,char **argv,void *p)
  965. {
  966.    if (!_checkok()) {
  967.       return -1;
  968.    }
  969.    return (getheap(Used));
  970. }
  971.  
  972. #endif
  973.  
  974. /* ------------------------ Memory subcmd-parser ------------------------- */
  975. int
  976. domem(int argc,char **argv,void *p)
  977. {
  978.     struct cmds Memcmds[] = {
  979. #ifdef MDEBUG
  980.         {"dump",        domdump,        0, 0, NULLCHAR},
  981. #endif
  982. #ifdef __CPLUSPLUS
  983.         {"freelist",    dofreelist,        0, 0, NULLCHAR},
  984. #endif
  985. #if(defined(PACKET) || defined(ETHER) || defined(SCC))
  986.         {"ibufsize",    doibufsize,        0, 0, NULLCHAR},
  987.         {"nibufs",        donibufs,        0, 0, NULLCHAR},
  988. #endif
  989. #if((defined __CPLUSPLUS) && defined(MDEBUG))
  990.         {"overview",    doOverview,        0, 0, NULLCHAR},
  991. #endif
  992.         {"reboot",        docoldst,        0, 0, NULLCHAR},
  993. #ifdef MDEBUG
  994.         {"record",        dorecord,        0, 0, NULLCHAR},
  995.         {"refiq",        dorefiq,        0, 0, NULLCHAR},
  996.         {"sizes",        dosizes,        0, 0, NULLCHAR},
  997.         {"snap",        dosnap,            0, 2, "snap start"},
  998. #endif
  999.         {"status",        dostat,            0, 0, NULLCHAR},
  1000.         {"thresh",        dothresh,        0, 0, NULLCHAR},
  1001. #if((defined __CPLUSPLUS) && defined(MDEBUG))
  1002.         {"usedlist",    dousedlist,        0, 0, NULLCHAR},
  1003. #endif
  1004.         {NULLCHAR},
  1005.     };
  1006.  
  1007.    return subcmd(Memcmds,argc,argv,p);
  1008. }
  1009.  
  1010.